//
//  NNWeakProxyController.swift
//  CommonTool
//
//  Created by tenroadshow on 24.2.22.
//

import Foundation
import UIKit

/* 对于Swift，所观察对象
 1. 必须用@objcMembers修饰
 2. 所观察的属性，必须用 dynamic修饰
 **/

typealias NNObjectValueChangedHandle = (([NSKeyValueChangeKey : Any]?) -> ())

fileprivate class NNKVOInfo: NSObject {
    var object: NSObject?
    var keyPath: String?
    var options: NSKeyValueObservingOptions = .initial
    var context: UnsafeMutableRawPointer?

    var objectValueChangeHandle: NNObjectValueChangedHandle?
}


class NNKVOProxy: NSObject {

    private var mutex = pthread_mutex_t()
    private var infos: [NNKVOInfo] = []

    // 添加观察者
    public func sf_addObserver(_ associatedObject: NSObject?,
                               forKeyPath keyPath: String?,
                               options: NSKeyValueObservingOptions,
                              context: UnsafeMutableRawPointer?,
                              objectChangedHandle: NNObjectValueChangedHandle?) {

        guard let oobject = associatedObject else { return }
        guard let kkeyPath = keyPath, !kkeyPath.isEmpty else { return }

        let kvoInfo = NNKVOInfo()
        kvoInfo.object = oobject
        kvoInfo.keyPath  = kkeyPath
        kvoInfo.options  = options
        kvoInfo.context  = context
        kvoInfo.objectValueChangeHandle = objectChangedHandle

        pthread_mutex_lock(&mutex);
        let contains = infos.contains { $0.keyPath == kvoInfo.keyPath && $0.object == kvoInfo.object}
        // 如果没有添加过，则可添加观察者；否则不能重复添加
        if !contains {
            infos.append(kvoInfo)
            // add observer
            oobject.addObserver(self,
                               forKeyPath: kkeyPath,
                               options: kvoInfo.options,
                               context: kvoInfo.context)
        }
        pthread_mutex_unlock(&mutex);
    }

    // 移除观察者
    public func sf_removeObserver(_ object: NSObject?, keyPath: String?) {
        guard let oobject = object else { return }
        guard let kkeyPath = keyPath, !kkeyPath.isEmpty else { return }
        pthread_mutex_lock(&mutex);
        if infos.first(where: { $0.keyPath == kkeyPath && $0.object == oobject }) != nil {
            infos.removeAll { $0.keyPath == kkeyPath && $0.object == oobject }
            oobject.removeObserver(self, forKeyPath: kkeyPath)
        }
        pthread_mutex_unlock(&mutex);
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard let kkeyPath = keyPath, !kkeyPath.isEmpty else { return }
        guard let oobject = object as? NSObject else { return }
        guard let kvoInfo = infos.first(where: { $0.keyPath == kkeyPath && $0.object == oobject }) else { return }
        kvoInfo.objectValueChangeHandle?(change)
    }
}



@objcMembers
class PPerson: NSObject {
    dynamic var name: NSString = ""
    dynamic var age: NSInteger = 10
}


class NNWeakProxyController: NNBaseViewController {
    var proxy: NNKVOProxy = NNKVOProxy()
    
    var person = PPerson()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let add = UIBarButtonItem(title: "添加",
                                    style: .done,
                                    target: self,
                                    action: #selector(sf_addObserver))
        let remove = UIBarButtonItem(title: "移除",
                                     style: .done,
                                     target: self,
                                     action: #selector(sf_removeObserver))
        navigationItem.rightBarButtonItems = [add, remove]
    }
    
   @objc func sf_addObserver() {
       proxy.sf_addObserver(person,
                                   forKeyPath: "age",
                                   options: [.old, .new],
                                   context: nil) { change in
           CC.log("值改变了")
           if let oldValue = change?[NSKeyValueChangeKey.oldKey] {
               CC.log("old: \(oldValue)")
           }
           
           if let newValue = change?[NSKeyValueChangeKey.newKey] {
               CC.log("new: \(newValue)")
           }
       }
       CC.log("添加了观察者")
    }
    
    @objc func sf_removeObserver() {
        proxy.sf_removeObserver(person, keyPath: "age")
        CC.log("移除了观察者")
    }
        
    
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        
        person.age = Int.random(in: 10...100)
        
    }
   
}
